package com.study.meng.bigevent.controller;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.jwt.JWTUtil;
import com.study.meng.bigevent.common.utils.ThreadLocalUtil;
import com.study.meng.bigevent.entity.Result;
import com.study.meng.bigevent.entity.User;
import com.study.meng.bigevent.service.UserService;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.hibernate.validator.constraints.URL;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.time.Duration;
import java.util.Map;

@RestController
@RequestMapping("/user")
// 开启参数校验
@Validated
public class UserController {
    @Resource
    private UserService userService;  // 用户服务层接口
    @Resource
    private RedisTemplate<String, String> redisTemplate;  // Redis操作模板

    /**
     * 用户注册接口
     *
     * @param user 包含用户名和密码的用户对象
     * @return 注册结果
     */
    @PostMapping("/register")
    public Result register(@Valid @RequestBody User user) {
        // 检查用户名是否已存在
        User u = userService.findByUserName(user.getUsername());
        if (u != null) {
            return Result.error(401, "用户名已存在");
        }
        // 对密码进行MD5加密
        user.setPassword(SecureUtil.md5(user.getPassword()));
        // 调用服务层注册用户
        boolean flag = userService.register(user);
        return flag ? Result.success("注册成功") : Result.error(402, "注册失败");
    }

    /**
     * 用户登录接口
     *
     * @param user 包含用户名和密码的用户对象
     * @return 登录成功返回JWT token，失败返回错误信息
     */
    @PostMapping("/login")
    public Result<String> login(@Valid @RequestBody User user) {
        // 验证用户名是否存在
        User u = userService.findByUserName(user.getUsername());
        if (u == null) {
            return Result.error(401, "用户名不存在");
        }
        // 验证密码是否正确（比较MD5加密后的值）
        if (!u.getPassword().equals(SecureUtil.md5(user.getPassword()))) {
            return Result.error(402, "密码错误");
        }
        // 生成JWT token，有效期15天
        String token = JWTUtil.createToken(Map.of("id", u.getId(), "username", u.getUsername(), "expire_time", System.currentTimeMillis() + 1000L * 60 * 60 * 24 * 15), "meng".getBytes());
        // 验证token是否生成成功
        // 将token存入Redis
        redisTemplate.opsForValue().set("Login:token:" + u.getId(), token, Duration.ofDays(15));
        // 将用户名存入ThreadLocal，方便后续获取当前用户信息
        ThreadLocalUtil.setCurrentUser(u.getId());
        // 返回登录成功的token
        return Result.success(token);
    }

    /**
     * 获取当前用户信息
     *
     * @param token JWT token
     * @return 用户详细信息
     */
    @GetMapping("/userInfo")
    public Result<User> userInfo(@RequestHeader("Authorization") String token) {
        // 从token中获取用户ID
        Integer userId = Integer.valueOf(JWTUtil.parseToken(token).getPayload("id").toString());
        // 调用服务层获取用户信息
        User user = userService.findByUserId(userId);
        if (user == null) {
            return Result.error(404, "用户不存在");
        }
        // 返回用户信息
        return Result.success(user);
    }

    /**
     * 更新用户信息
     *
     * @param user 包含更新信息的用户对象
     * @return 更新结果
     */
    @PutMapping("/update")
    public Result<String> update(@Valid @RequestBody User user) {
        // 调用服务层更新用户基本信息
        boolean flag = userService.update(user);
        return flag ? Result.success() : Result.error(404, "更新失败");
    }

    /**
     * 更新用户头像
     */
    @PatchMapping("/updateAvatar")
    public Result<String> updateAvatar(@RequestParam("avatar") @URL String avatar) {
        // 调用服务层更新头像
        boolean flag = userService.updateAvatar(avatar);
        return flag ? Result.success("头像更新成功") : Result.error(404, "头像更新失败");
    }

    /**
     * 更新密码
     */
    @PatchMapping("/updatePwd")
    public Result<String> updatePassword(@RequestBody @Valid Map<String, String> passwordMap) {
        String oldPassword = passwordMap.get("oldPassword");
        String newPassword = passwordMap.get("newPassword");
        String confirmPassword = passwordMap.get("confirmPassword");// 确认密码未使用，直接忽略
        // 验证旧密码、 新密码和确认密码不能为空
        if (!StringUtils.hasLength(oldPassword) || !StringUtils.hasLength(newPassword) || !StringUtils.hasLength(confirmPassword)) {
            return Result.error(400, "密码不能为空");
        }
        // 验证新密码和确认密码是否一致
        if (!newPassword.equals(confirmPassword)) {
            return Result.error(400, "新密码和确认密码不一致");
        }
        // 验证当前用户只能修改自己的密码
        Integer userId = ThreadLocalUtil.getCurrentUser();
        User user = userService.findByUserId(userId);
        if (user == null) {
            return Result.error(404, "用户不存在");
        }

        // 验证旧密码是否正确
        if (!user.getPassword().equals(SecureUtil.md5(oldPassword))) {
            return Result.error(401, "旧密码错误");
        }
        // 更新密码
        user.setPassword(SecureUtil.md5(newPassword));
        boolean flag = userService.udpatePwd(user);
        // 如果更新成功，删除Redis中的token
        if (flag) {
            redisTemplate.delete("Login:token:" + userId);
            // 从ThreadLocal中删除用户信息
            ThreadLocalUtil.remove();
        }
        return flag ? Result.success("密码更新成功") : Result.error(404, "密码更新失败");
    }

    /**
     * 用户退出登录接口
     *
     * @param token
     */
    @DeleteMapping("/logout")
    public Result<String> logout(@RequestHeader("Authorization") String token) {
        // 从token中获取用户ID
        int userId = Integer.parseInt(JWTUtil.parseToken(token).getPayload("id").toString());
        // 从Redis中删除token
        redisTemplate.delete("Login:token:" + userId);
        // 从ThreadLocal中删除用户信息
        return Result.success("退出成功");
    }

    /**
     * 删除用户接口
     *
     * @param token
     */
    @DeleteMapping("/delete")
    public Result<String> delete(@RequestHeader("Authorization") String token) {
        // 从token中获取用户ID
        Integer userId = Integer.valueOf(JWTUtil.parseToken(token).getPayload("id").toString());
        // 调用服务层删除用户
        boolean flag = userService.delete(userId);
        return flag ? Result.success("删除成功") : Result.error(404, "删除失败");
    }
}

